9.7 IsとAs
ラップされたエラーとマッチするためにerrorsパッケージのIs関数とAs関数を使用する
erros.Isの実装例
code:go
package main
import (
"errors"
"fmt"
"os"
)
func fileChecker(name string) error {
f, err := os.Open(name)
if err != nil {
return fmt.Errorf("in fileChecker: %w", err)
}
f.Close()
return nil
}
func main() {
err := fileChecker("not_here.txt")
if err != nil {
if errors.Is(err, os.ErrNotExist) {
fmt.Println("That file doesn't exist")
}
}
}
独自のメソッドIsを定義することでカスタムエラーのフィールドで比較を行うこともできる
code:go
package main
import (
"errors"
"fmt"
)
type StatusErr struct {
Status int
Message string
}
func (e StatusErr) Error() string {
return e.Message
}
// Isメソッドを実装
func (e StatusErr) Is(target error) bool {
t, ok := target.(StatusErr)
if !ok {
return false
}
return e.Status == t.Status
}
func main() {
err := fmt.Errorf("wrap: %w", StatusErr{Status: 404, Message: "not found"})
target := StatusErr{Status: 404}
fmt.Println(errors.Is(err, target)) // true
}
errors.Asの実装例
第二引数はエラー、もしくは、インタフェースのポインタ以外の場合はパニックを起こす
独自のAsメソッドも定義できるが、リフレクションが必要になるため一般的でない状況のみで行うべき
code:go
package main
import (
"errors"
"fmt"
)
type MyErr struct {
Codes []int
}
func (me MyErr) CodeVals() []int {
return me.Codes
}
func (me MyErr) Error() string {
return fmt.Sprintf("codes: %v", me.Codes)
}
func AFunctionThatReturnsAnError() error {
return MyErr{Codes: []int{1, 1, 2, 3, 5, 8}}
}
func main() {
err := AFunctionThatReturnsAnError()
var myErr MyErr
if errors.As(err, &myErr) {
}
var coder interface {
CodeVals() []int
}
if errors.As(err, &coder) {
}
}